#include "ui.h"

//PUBLIC FUNCTIONS
Ui::Ui(Pcqc *pcqc)
{
    motor = pcqc;
    isCameraCentered = false;
    filesNamesList = new QStringList;
    setupMenuBar();
    setupStatusBar();
    setupMainLayout();
    setWindowTitle(tr("3d-complete"));
    resize(1024,768);
}

Ui::~Ui()
{
    delete viewer;
}

Pcqc* Ui::getMotor()
{
    return motor;
}

pcl::visualization::PCLVisualizer* Ui::getViewer()
{
    return viewer;
}

pcl::visualization::PCLVisualizer* Ui::getDialogViewer()
{
    return dialogViewer;
}

QVTKWidget* Ui::getViewerWidget()
{
    return qvtkVisualizer;
}

QDialog* Ui::getComponentDialog()
{
    return addComponentDialog;
}

// SLOT FUNCTIONS
void Ui::about()
{
    QMessageBox::about(this, tr("About 3d-complete"), tr("The <b>3d-complete</b> is super awesome!It's worth 30 cum laude!") );
}

void Ui::aboutPCL()
{
    QMessageBox::about(this, tr("About PCL"), tr("The Point Cloud Library (or PCL) is a large scale,"
                                                 "open project for 3D point cloud processing.") );
}

void Ui::browseLoadTarget()
{
    QString fileName = QFileDialog::getOpenFileName(this, tr("Load Target Point Cloud"), "/home", tr("Point Clouds *.pcd (*.pcd);;All Files (*.*)"));
    if(fileName != "")
    {
        pathTField->setText(fileName);
        if(motor->loadTargetCloud(pathTField->displayText()))
        {
            statusBar()->showMessage(pathTField->displayText()+QString(" successfully loaded!"));
            isCameraCentered = false;
        }
        else statusBar()->showMessage(QString("Couldn't load the target point cloud, maybe the path or the filename are not correct."));
    }

}

void Ui::browseSourceFolder()
{
    QString folderName = QFileDialog::getExistingDirectory(this, QString("Select Source Point Clouds' Folder"), "/home", QFileDialog::ShowDirsOnly);
    if(folderName != "" && folderName != pathSourceFolderField->text())
    {
        pathSourceFolderField->setText(folderName);
        QDir currentDir(folderName);
        *filesNamesList = currentDir.entryList( QStringList(QString("*.pcd")), QDir::Files | QDir::NoSymLinks );
        if(filesNamesList->isEmpty())
        {
            statusBar()->showMessage(QString("Couldn't find any point cloud in the specified folder"));
            sourceCloudsComboBox->clear();
        }
        else
        {
            sourceCloudsComboBox->clear(); // Clear the list from files detecred in other folders.
            sourceCloudsComboBox->addItems(*filesNamesList);
            sourceCloudsComboBox->setCurrentIndex(0);
            if( motor->loadSourceCloud( folderName + "/" + sourceCloudsComboBox->currentText() ) )
            {
                statusBar()->showMessage( sourceCloudsComboBox->currentText() + QString(" successfully loaded!") );
                isCameraCentered = false;
            }
            else statusBar()->showMessage(QString("Couldn't load the source point cloud, maybe the path or the filename are not correct."));
        }
    }

}

void Ui::loadSourceCloud(QString fileName)
{
    if( motor->loadSourceCloud( pathSourceFolderField->text() + "/" + sourceCloudsComboBox->currentText() ) )
    {
        statusBar()->showMessage( sourceCloudsComboBox->currentText() + QString(" successfully loaded!") );
        isCameraCentered = false;
    }
    else statusBar()->showMessage(QString("Couldn't load the source point cloud, maybe the path or the filename are not correct."));
}

void Ui::clearAll()
{
    viewer->removeAllPointClouds();
}

void Ui::openComponentDialog()
{
    addComponentDialog = new QDialog(this); // set as child of Ui, to be sure that it will be deleted in the end.

    QVBoxLayout *dialogLayout = new QVBoxLayout; // create vertical layout

    QVTKWidget *dialogVisualizer = new QVTKWidget; // create qvtk widget
    dialogViewer = new pcl::visualization::PCLVisualizer("Dialog Viewer", false);
    dialogVisualizer->SetRenderWindow(dialogViewer->getRenderWindow()); // set as render window the render window of the dialog visualizer
    dialogViewer->setupInteractor(dialogVisualizer->GetInteractor(), dialogVisualizer->GetRenderWindow()); // tells the visualizer what interactor is using now and for what window
    dialogViewer->getInteractorStyle()->setKeyboardModifier(pcl::visualization::INTERACTOR_KB_MOD_SHIFT); // ripristina input system of original visualizer (shift+click for points)
    pcl::PointCloud<pcl::PointXYZRGB>::Ptr temp = motor->getTargetCloud();
    pcl::visualization::PointCloudColorHandlerRGBField<pcl::PointXYZRGB> rgb(temp);
    dialogViewer->addPointCloud<pcl::PointXYZRGB>(temp, rgb, "cloud");
    dialogViewer->setBackgroundColor(0.5, 0.5, 0.5);
    dialogViewer->initCameraParameters();
    dialogViewer->resetCamera();
    componentCallbackConnection = dialogViewer->registerPointPickingCallback(&pointPickCallbackSelectComponent, this); // segmentation callback

    QLineEdit *addComponentDialogName  = new QLineEdit("Insert Component Name");
    addComponentDialogName->setObjectName("componentname");

    QHBoxLayout *dialogControlsLayout = new QHBoxLayout;

    QVBoxLayout *buttonsBox = new QVBoxLayout;
    QRadioButton *clusterMatchingButton = new QRadioButton("Cluster Matching");
    clusterMatchingButton->setObjectName("clusterMatchingButton");
    clusterMatchingButton->setChecked(true);
    QRadioButton *shapeMatchingButton = new QRadioButton("Shape Matching");
    shapeMatchingButton->setObjectName("shapeMatchingButton");
    QPushButton *showSegButton = new QPushButton("Segment Component");
    connect(showSegButton, SIGNAL(clicked()), this, SLOT(segmentComponent()));
    buttonsBox->addWidget(clusterMatchingButton);
    buttonsBox->addWidget(shapeMatchingButton);
    buttonsBox->addWidget(showSegButton);

    QVBoxLayout *numbersBox = new QVBoxLayout;
    QHBoxLayout* colorLayout = new QHBoxLayout;
    QLabel *colorLabel = new QLabel(QString("Color threshold"));
    QColor *selectedColor = new QColor(0, 0, 0, 255); // initialize color at black
    QPushButton *colorBox = new QPushButton("+-100");
    colorBox->setObjectName("colorbox");
    colorBox->setStyleSheet(colorToStyleSheet(selectedColor));
    colorBox->setMaximumWidth(50);
    QSlider *setColThresholdBar = new QSlider(Qt::Horizontal);
    setColThresholdBar->setRange(0,255);
    setColThresholdBar->setValue(100);
    motor->setColorSegThreshold(100);
    setColThresholdBar->setObjectName("sliderColor");
    connect(setColThresholdBar, SIGNAL(sliderReleased()), this, SLOT(setColorThreshold()));
    colorLayout->addWidget(colorBox);
    colorLayout->addWidget(setColThresholdBar);

    QHBoxLayout* clusterLayout = new QHBoxLayout;
    QLabel *clusterLabel = new QLabel(QString("Clustering threshold"));
    QLineEdit *clusterBox = new QLineEdit("1");
    clusterBox->setReadOnly(true);
    clusterBox->setObjectName("clusterbox");
    clusterBox->setMaxLength(5);
    clusterBox->setMaximumWidth(50);
    QSlider *setCluThresholdBar = new QSlider(Qt::Horizontal);
    setCluThresholdBar->setRange(0,5000);
    setCluThresholdBar->setValue(1000);
    motor->setClusterSegThreshold(1000);
    setCluThresholdBar->setObjectName("sliderCluster");
    connect(setCluThresholdBar, SIGNAL(sliderReleased()), this, SLOT(setClusterThreshold()));
    clusterLayout->addWidget(clusterBox);
    clusterLayout->addWidget(setCluThresholdBar);

    QHBoxLayout* shapeSkinLayout = new QHBoxLayout;
    QLabel *shapeSkinLabel = new QLabel(QString("Shape skin thickness"));
    QLineEdit* shapeSkinBox = new QLineEdit;
    shapeSkinBox->setObjectName("shapeSkinBox");
    shapeSkinBox->setMaxLength(5);
    shapeSkinBox->setMaximumWidth(50);
    shapeSkinBox->setText(QString("1"));
    shapeSkinBox->setEnabled(false);
    connect(shapeMatchingButton, SIGNAL(toggled(bool)), shapeSkinBox, SLOT(setEnabled(bool)));
    QSlider *setSkinThicknessBar = new QSlider(Qt::Horizontal);
    setSkinThicknessBar->setRange(0,5000);
    setSkinThicknessBar->setValue(1000);
    motor->setShapeMatchingThickness(1000);
    setSkinThicknessBar->setObjectName("sliderSkin");
    setSkinThicknessBar->setEnabled(false);
    connect(setSkinThicknessBar, SIGNAL(sliderReleased()), this, SLOT(setSkinThickness()));
    connect(shapeMatchingButton, SIGNAL(toggled(bool)), setSkinThicknessBar, SLOT(setEnabled(bool)));
    shapeSkinLayout->addWidget(shapeSkinBox);
    shapeSkinLayout->addWidget(setSkinThicknessBar);

    numbersBox->addWidget(clusterLabel);
    numbersBox->addLayout(clusterLayout);
    numbersBox->addWidget(colorLabel);
    numbersBox->addLayout(colorLayout);
    numbersBox->addWidget(shapeSkinLabel);
    numbersBox->addLayout(shapeSkinLayout);

    dialogControlsLayout->addLayout(buttonsBox);
    dialogControlsLayout->addLayout(numbersBox);

    QPushButton *saveComponent = new QPushButton("Save to component list");
    saveComponent->setDefault(true); // default button, pressed if enter is pressed
    connect(saveComponent, SIGNAL(clicked()), this, SLOT(saveComponent()));

    dialogLayout->addWidget(dialogVisualizer);
    dialogLayout->addWidget(addComponentDialogName);
    dialogLayout->addLayout(dialogControlsLayout);
    dialogLayout->addWidget(saveComponent);
    addComponentDialog->setLayout(dialogLayout);

    // DIALOG EXECUTION
    dialogLayout->deleteLater(); // delete dialog layout when the control returns to the event loop from which deleteLater() was called (after exec i guess)
    addComponentDialog->resize(500,600);
    addComponentDialog->exec();
    componentCallbackConnection.disconnect(); // disconnect the callback function from the viewer
    delete dialogViewer; // finita l'esecuzione, deallocare il viewer (deallocare altra eventuale memoria non indirizzata nel QObject tree).
}

void Ui::setComponentDialogCallback()
{
    dialogViewer->registerPointPickingCallback(&pointPickCallbackSelectComponent, this);
}

void Ui::resetComponentDialogCallback()
{
    dialogViewer->registerPointPickingCallback(&pointPickCallback, this);
    dialogViewer->updatePointCloud(motor->getTargetCloud(),"cloud");
}

void Ui::setClusterThreshold()
{
    QSlider *slider= addComponentDialog->findChild<QSlider *>("sliderCluster");
    motor->setClusterSegThreshold(slider->value());
    QLineEdit *clusterbox = addComponentDialog->findChild<QLineEdit *>("clusterbox");
    clusterbox->setText(QString("%1").arg((float)slider->value() / 1000));
}

void Ui::setColorThreshold()
{
    QSlider *slider= addComponentDialog->findChild<QSlider *>("sliderColor");
    motor->setColorSegThreshold(slider->value());
    QPushButton *colorbox = addComponentDialog->findChild<QPushButton *>("colorbox");
    colorbox->setText(QString("+-%1").arg(slider->value()));
}

void Ui::setSkinThickness()
{
    QSlider *slider= addComponentDialog->findChild<QSlider *>("sliderSkin");
    motor->setShapeMatchingThickness(slider->value());
    QLineEdit *shapeSkinBox = addComponentDialog->findChild<QLineEdit *>("shapeSkinBox");
    shapeSkinBox->setText(QString("%1").arg( (float)slider->value() / 1000) );
}

void Ui::setScoreDistanceThreshold()
{
    QSlider *slider= resultsBox->findChild<QSlider *>("scoreDistanceSlider");
    motor->setScoreDistanceThreshold(slider->value()/100.0f*6.0f,slider->value()/100.0f*8.0f);
}


void Ui::segmentComponent()
{
    if(motor->componentSegmentation())
        statusBar()->showMessage("Segmented new component.");
    else statusBar()->showMessage("Couldn't segment this selection.");
    dialogViewer->updatePointCloud(motor->getNewComponentCloud(),"cloud");
}

void Ui::saveComponent()
{
    QLineEdit* componentname = addComponentDialog->findChild<QLineEdit *>("componentname");
    QRadioButton* cmButton = addComponentDialog->findChild<QRadioButton *>("clusterMatchingButton");
    if( motor->componentSave( componentname->text(), cmButton->isChecked() ) )
    {
        componentsList->addItem(componentname->text());
        statusBar()->showMessage("Component successfully saved!");
    }
    else statusBar()->showMessage("Couldn't save this component: check component name.");
}

void Ui::deleteComponent()
{
    if(componentsList->selectedItems().isEmpty())
        statusBar()->showMessage("Can't delete component: no components selected.");
    else
    {
        if( motor->componentDelete(componentsList->selectedItems().first()->text()) )
        {
            qDeleteAll(componentsList->selectedItems()); // delete entry from components list
            statusBar()->showMessage("Components deleted.");
        }
        else statusBar()->showMessage("Can't delete component: no matching name found in cloud handler.");

    }
}

void Ui::autoComponentDetection()
{
    if(motor->getTargetCloud()->empty())
    {
        statusBar()->showMessage(QString("Load a reference cloud before starting."));
        return;
    }
    int componentsNumber = motor->findTargetComponents();
    statusBar()->showMessage(QString("Automatic components detection found %1 components.").arg(componentsNumber));
    QMap<QString, Component>* targetComponentsListMotor = motor->getTargetComponentsList();
    QMapIterator<QString, Component> iter(*targetComponentsListMotor);
    while(iter.hasNext())
    {
        QString currentComponentName = iter.next().key();
        if( componentsList->findItems(currentComponentName, Qt::MatchExactly).isEmpty() )
        {
            componentsList->addItem(currentComponentName);
        }
    }
}

void Ui::openCheckDialog()
{
    addCheckDialog = new QDialog(this); // set as child of Ui, to be sure that it will be deleted in the end.
    QVBoxLayout *dialogLayout = new QVBoxLayout;
    QTabWidget *tabWidget = new QTabWidget();
    tabWidget->setObjectName(QString("tabwidget"));

    // PRESENCE
    QWidget *presenceTab = new QWidget();
    QVBoxLayout *presenceTabLayout = new QVBoxLayout();
    QLabel *presenceCheckNameLabel = new QLabel(QString("Check ID:"));
    QLabel *presenceComponentName = new QLabel();
    presenceComponentName->setObjectName("componentname"); // set object name to be easily found with findChild function
    QLabel *presenceCheckType = new QLabel("-presence");
    presenceCheckType->setObjectName("checktype"); // set object name to be easily found with findChild function
    QGridLayout *presenceFullNameLayout = new QGridLayout(); // use this grid layot to compone and display the check's full name (ID) that will be saved in the checks' list
    presenceFullNameLayout->setHorizontalSpacing(0);
    presenceFullNameLayout->setColumnStretch(0,0);
    presenceFullNameLayout->setColumnStretch(1,5);
    presenceFullNameLayout->addWidget(presenceComponentName, 0, 0);
    presenceFullNameLayout->addWidget(presenceCheckType, 0, 1);
    QLabel *presenceComponentLabel = new QLabel(QString("Component analyzed:"));
    QComboBox *presenceComponentBox = new QComboBox();
    presenceComponentBox->setObjectName("combobox");
    setupChecksComboBox(presenceComponentBox); // fill the combo box with the names of the components in the components' list
    presenceComponentName->setText(presenceComponentBox->currentText()); // set the component name of the check with the selected component in the combo box...
    connect( presenceComponentBox, SIGNAL(currentIndexChanged(QString)), presenceComponentName, SLOT(setText(QString)) ); // ...and do it automatically
    QLabel *presenceThresholdLabel = new QLabel(QString("Maximum score to be found:"));
    QLabel *presenceThresholdNumber = new QLabel();
    QSlider *presenceThresholdSlider = new QSlider(Qt::Horizontal);
    connect(presenceThresholdSlider, SIGNAL(valueChanged(int)), presenceThresholdNumber, SLOT(setNum(int)));
    presenceThresholdSlider->setRange(0,40);
    presenceThresholdSlider->setValue(20);
    QPushButton *presenceAdd = new QPushButton(QString("Add Check"));
    connect(presenceAdd, SIGNAL(clicked()), this, SLOT(saveCheck()));
    QPushButton *presenceAddAll = new QPushButton(QString("Add Check For Every Component"));
    connect(presenceAddAll, SIGNAL(clicked()), this, SLOT(saveCheckAll()));
    presenceTabLayout->addWidget(presenceCheckNameLabel);
    presenceTabLayout->addLayout(presenceFullNameLayout);
    presenceTabLayout->addWidget(presenceComponentLabel);
    presenceTabLayout->addWidget(presenceComponentBox);
    presenceTabLayout->addWidget(presenceThresholdLabel);
    presenceTabLayout->addWidget(presenceThresholdNumber);
    presenceTabLayout->addWidget(presenceThresholdSlider);
    presenceTabLayout->addWidget(presenceAdd);
    presenceTabLayout->addWidget(presenceAddAll);
    presenceTab->setLayout(presenceTabLayout);

    // POSITION
    QWidget *positionTab = new QWidget();
    QVBoxLayout *positionTabLayout = new QVBoxLayout();
    QLabel *positionCheckNameLabel = new QLabel(QString("Check ID:"));
    QLabel *positionComponentName = new QLabel();
    positionComponentName->setObjectName("componentname"); // set object name to be easily found with findChild function
    QLabel *positionCheckType = new QLabel("-position");
    positionCheckType->setObjectName("checktype"); // set object name to be easily found with findChild function
    QGridLayout *positionFullNameLayout = new QGridLayout(); // use this grid layot to compone and display the check's full name (ID) that will be saved in the checks' list
    positionFullNameLayout->setHorizontalSpacing(0);
    positionFullNameLayout->setColumnStretch(0,0);
    positionFullNameLayout->setColumnStretch(1,5);
    positionFullNameLayout->addWidget(positionComponentName, 0, 0);
    positionFullNameLayout->addWidget(positionCheckType, 0, 1);
    QLabel *positionComponentLabel = new QLabel(QString("Component analyzed:"));
    QComboBox *positionComponentBox = new QComboBox();
    positionComponentBox->setObjectName("combobox");
    setupChecksComboBox(positionComponentBox); // fill the combo box with the names of the components in the components' list
    positionComponentName->setText(positionComponentBox->currentText()); // set the component name of the check with the selected component in the combo box...
    connect( positionComponentBox, SIGNAL(currentIndexChanged(QString)), positionComponentName, SLOT(setText(QString)) ); // ...and do it automatically
    QLabel *positionThresholdLabel = new QLabel(QString("Minimum % of points to be found (100% = more points than target):"));
    QLabel *positionThresholdNumber = new QLabel();
    QSlider *positionThresholdSlider = new QSlider(Qt::Horizontal);
    connect(positionThresholdSlider, SIGNAL(valueChanged(int)), positionThresholdNumber, SLOT(setNum(int)));
    positionThresholdSlider->setRange(0,100);
    positionThresholdSlider->setValue(30);
    QPushButton *positionAdd = new QPushButton(QString("Add Check"));
    connect(positionAdd, SIGNAL(clicked()), this, SLOT(saveCheck()));
    QPushButton *positionAddAll = new QPushButton(QString("Add Check For Every Component"));
    connect(positionAddAll, SIGNAL(clicked()), this, SLOT(saveCheckAll()));
    positionTabLayout->addWidget(positionCheckNameLabel);
    positionTabLayout->addLayout(positionFullNameLayout);
    positionTabLayout->addWidget(positionComponentLabel);
    positionTabLayout->addWidget(positionComponentBox);
    positionTabLayout->addWidget(positionThresholdLabel);
    positionTabLayout->addWidget(positionThresholdNumber);
    positionTabLayout->addWidget(positionThresholdSlider);
    positionTabLayout->addWidget(positionAdd);
    positionTabLayout->addWidget(positionAddAll);
    positionTab->setLayout(positionTabLayout);

    // INCLINATION
    QWidget *inclinationTab = new QWidget();
    QVBoxLayout *inclinationTabLayout = new QVBoxLayout();
    QLabel *inclinationCheckNameLabel = new QLabel(QString("Check ID:"));
    QLabel *inclinationComponentName = new QLabel();
    inclinationComponentName->setObjectName("componentname");
    QLabel *inclinationCheckType = new QLabel("-inclination");
    inclinationCheckType->setObjectName("checktype");
    QGridLayout *inclinationFullNameLayout = new QGridLayout();
    inclinationFullNameLayout->setHorizontalSpacing(0);
    inclinationFullNameLayout->setColumnStretch(0,0);
    inclinationFullNameLayout->setColumnStretch(1,5);
    inclinationFullNameLayout->addWidget(inclinationComponentName, 0, 0);
    inclinationFullNameLayout->addWidget(inclinationCheckType, 0, 1);
    QLabel *inclinationComponentLabel = new QLabel(QString("Component analyzed:"));
    QComboBox *inclinationComponentBox = new QComboBox();
    inclinationComponentBox->setObjectName("combobox");
    setupChecksComboBox(inclinationComponentBox);
    inclinationComponentName->setText(inclinationComponentBox->currentText());
    connect( inclinationComponentBox, SIGNAL(currentIndexChanged(QString)), inclinationComponentName, SLOT(setText(QString)) );
    QLabel *inclinationThresholdLabel = new QLabel(QString("Angular difference in decimal degrees (10 = 1 degree):"));
    QLabel *inclinationThresholdNumber = new QLabel();
    QSlider *inclinationThresholdSlider = new QSlider(Qt::Horizontal);
    connect(inclinationThresholdSlider, SIGNAL(valueChanged(int)), inclinationThresholdNumber, SLOT(setNum(int)));
    inclinationThresholdSlider->setRange(0,100);
    inclinationThresholdSlider->setValue(30);
    QPushButton *inclinationAdd = new QPushButton(QString("Add Check"));
    connect(inclinationAdd, SIGNAL(clicked()), this, SLOT(saveCheck()));
    QPushButton *inclinationAddAll = new QPushButton(QString("Add Check For Every Component"));
    connect(inclinationAddAll, SIGNAL(clicked()), this, SLOT(saveCheckAll()));
    inclinationTabLayout->addWidget(inclinationCheckNameLabel);
    inclinationTabLayout->addLayout(inclinationFullNameLayout);
    inclinationTabLayout->addWidget(inclinationComponentLabel);
    inclinationTabLayout->addWidget(inclinationComponentBox);
    inclinationTabLayout->addWidget(inclinationThresholdLabel);
    inclinationTabLayout->addWidget(inclinationThresholdNumber);
    inclinationTabLayout->addWidget(inclinationThresholdSlider);
    inclinationTabLayout->addWidget(inclinationAdd);
    inclinationTabLayout->addWidget(inclinationAddAll);
    inclinationTab->setLayout(inclinationTabLayout);

    // ORIENTATION
    QWidget *orientationTab = new QWidget();
    QVBoxLayout *orientationTabLayout = new QVBoxLayout();
    QLabel *orientationCheckNameLabel = new QLabel(QString("Check ID:"));
    QLabel *orientationComponentName = new QLabel();
    orientationComponentName->setObjectName("componentname");
    QLabel *orientationCheckType = new QLabel("-orientation");
    orientationCheckType->setObjectName("checktype");
    QGridLayout *orientationFullNameLayout = new QGridLayout();
    orientationFullNameLayout->setHorizontalSpacing(0);
    orientationFullNameLayout->setColumnStretch(0,0);
    orientationFullNameLayout->setColumnStretch(1,5);
    orientationFullNameLayout->addWidget(orientationComponentName, 0, 0);
    orientationFullNameLayout->addWidget(orientationCheckType, 0, 1);
    QLabel *orientationComponentLabel = new QLabel(QString("Component analyzed:"));
    QComboBox *orientationComponentBox = new QComboBox();
    orientationComponentBox->setObjectName("combobox");
    setupChecksComboBox(orientationComponentBox);
    orientationComponentName->setText(orientationComponentBox->currentText());
    connect( orientationComponentBox, SIGNAL(currentIndexChanged(QString)), orientationComponentName, SLOT(setText(QString)) );
    QLabel *orientationThresholdLabel = new QLabel(QString("Angular difference in decimal degrees (10 = 1 degree):"));
    QLabel *orientationThresholdNumber = new QLabel();
    QSlider *orientationThresholdSlider = new QSlider(Qt::Horizontal);
    connect(orientationThresholdSlider, SIGNAL(valueChanged(int)), orientationThresholdNumber, SLOT(setNum(int)));
    orientationThresholdSlider->setRange(0,100);
    orientationThresholdSlider->setValue(50);
    QPushButton *orientationAdd = new QPushButton(QString("Add Check"));
    connect(orientationAdd, SIGNAL(clicked()), this, SLOT(saveCheck()));
    QPushButton *orientationAddAll = new QPushButton(QString("Add Check For Every Component"));
    connect(orientationAddAll, SIGNAL(clicked()), this, SLOT(saveCheckAll()));
    orientationTabLayout->addWidget(orientationCheckNameLabel);
    orientationTabLayout->addLayout(orientationFullNameLayout);
    orientationTabLayout->addWidget(orientationComponentLabel);
    orientationTabLayout->addWidget(orientationComponentBox);
    orientationTabLayout->addWidget(orientationThresholdLabel);
    orientationTabLayout->addWidget(orientationThresholdNumber);
    orientationTabLayout->addWidget(orientationThresholdSlider);
    orientationTabLayout->addWidget(orientationAdd);
    orientationTabLayout->addWidget(orientationAddAll);
    orientationTab->setLayout(orientationTabLayout);

    // COLOR
    QWidget *colorTab = new QWidget();
    QVBoxLayout *colorTabLayout = new QVBoxLayout();
    QLabel *colorCheckNameLabel = new QLabel(QString("Check ID:"));
    QLabel *colorComponentName = new QLabel();
    colorComponentName->setObjectName("componentname"); // set object name to be easily found with findChild function
    QLabel *colorCheckType = new QLabel("-color");
    colorCheckType->setObjectName("checktype"); // set object name to be easily found with findChild function
    QGridLayout *colorFullNameLayout = new QGridLayout(); // use this grid layot to compone and display the check's full name (ID) that will be saved in the checks' list
    colorFullNameLayout->setHorizontalSpacing(0);
    colorFullNameLayout->setColumnStretch(0,0);
    colorFullNameLayout->setColumnStretch(1,5);
    colorFullNameLayout->addWidget(colorComponentName, 0, 0);
    colorFullNameLayout->addWidget(colorCheckType, 0, 1);
    QLabel *colorComponentLabel = new QLabel(QString("Component analyzed:"));
    QComboBox *colorComponentBox = new QComboBox();
    colorComponentBox->setObjectName("combobox");
    setupChecksComboBox(colorComponentBox); // fill the combo box with the names of the components in the components' list
    colorComponentName->setText(colorComponentBox->currentText()); // set the component name of the check with the selected component in the combo box...
    connect( colorComponentBox, SIGNAL(currentIndexChanged(QString)), colorComponentName, SLOT(setText(QString)) ); // ...and do it automatically
    //    QLabel *colorAverageLabel = new QLabel("Average color:");
    //    QPushButton *colorAverageButton = new QPushButton();
    //    colorAverageButton->setObjectName("averagecolor");
    //    colorAverageButton->setMaximumWidth(50);
    //    colorAverageButton->setStyleSheet(colorToStyleSheet(selectedColor));
    QLabel *colorThresholdLabel = new QLabel(QString("Color tolerance:"));
    QLabel *colorThresholdNumber = new QLabel();
    QSlider *colorThresholdSlider = new QSlider(Qt::Horizontal);
    connect(colorThresholdSlider, SIGNAL(valueChanged(int)), colorThresholdNumber, SLOT(setNum(int)));
    colorThresholdSlider->setRange(0,255);
    colorThresholdSlider->setValue(50);
    QPushButton *colorAdd = new QPushButton(QString("Add Check"));
    connect(colorAdd, SIGNAL(clicked()), this, SLOT(saveCheck()));
    QPushButton *colorAddAll = new QPushButton(QString("Add Check For Every Component"));
    connect(colorAddAll, SIGNAL(clicked()), this, SLOT(saveCheckAll()));
    colorTabLayout->addWidget(colorCheckNameLabel);
    colorTabLayout->addLayout(colorFullNameLayout);
    colorTabLayout->addWidget(colorComponentLabel);
    colorTabLayout->addWidget(colorComponentBox);
    //    colorTabLayout->addWidget(colorAverageLabel);
    //    colorTabLayout->addWidget(colorAverageButton);
    colorTabLayout->addWidget(colorThresholdLabel);
    colorTabLayout->addWidget(colorThresholdNumber);
    colorTabLayout->addWidget(colorThresholdSlider);
    colorTabLayout->addWidget(colorAdd);
    colorTabLayout->addWidget(colorAddAll);
    colorTab->setLayout(colorTabLayout);

    // HEIGHT
    QWidget *heightTab = new QWidget();
    QVBoxLayout *heightTabLayout = new QVBoxLayout();
    QLabel *heightCheckNameLabel = new QLabel(QString("Check ID:"));
    QLabel *heightComponentName = new QLabel();
    heightComponentName->setObjectName("componentname");
    QLabel *heightCheckType = new QLabel("-height");
    heightCheckType->setObjectName("checktype");
    QGridLayout *heightFullNameLayout = new QGridLayout();
    heightFullNameLayout->setHorizontalSpacing(0);
    heightFullNameLayout->setColumnStretch(0,0);
    heightFullNameLayout->setColumnStretch(1,5);
    heightFullNameLayout->addWidget(heightComponentName, 0, 0);
    heightFullNameLayout->addWidget(heightCheckType, 0, 1);
    QLabel *heightComponentLabel = new QLabel(QString("Component analyzed:"));
    QComboBox *heightComponentBox = new QComboBox();
    heightComponentBox->setObjectName("combobox");
    setupChecksComboBox(heightComponentBox);
    heightComponentName->setText(heightComponentBox->currentText());
    connect( heightComponentBox, SIGNAL(currentIndexChanged(QString)), heightComponentName, SLOT(setText(QString)) );
    QLabel *heightThresholdLabel = new QLabel(QString("Height difference in decimal millimeters (10 = 1 mm):"));
    QLabel *heightThresholdNumber = new QLabel();
    QSlider *heightThresholdSlider = new QSlider(Qt::Horizontal);
    connect(heightThresholdSlider, SIGNAL(valueChanged(int)), heightThresholdNumber, SLOT(setNum(int)));
    heightThresholdSlider->setRange(0,100);
    heightThresholdSlider->setValue(30);
    QPushButton *heightAdd = new QPushButton(QString("Add Check"));
    connect(heightAdd, SIGNAL(clicked()), this, SLOT(saveCheck()));
    QPushButton *heightAddAll = new QPushButton(QString("Add Check For Every Component"));
    connect(heightAddAll, SIGNAL(clicked()), this, SLOT(saveCheckAll()));
    heightTabLayout->addWidget(heightCheckNameLabel);
    heightTabLayout->addLayout(heightFullNameLayout);
    heightTabLayout->addWidget(heightComponentLabel);
    heightTabLayout->addWidget(heightComponentBox);
    heightTabLayout->addWidget(heightThresholdLabel);
    heightTabLayout->addWidget(heightThresholdNumber);
    heightTabLayout->addWidget(heightThresholdSlider);
    heightTabLayout->addWidget(heightAdd);
    heightTabLayout->addWidget(heightAddAll);
    heightTab->setLayout(heightTabLayout);

    // RADIUS
    QWidget *radiusTab = new QWidget();
    QVBoxLayout *radiusTabLayout = new QVBoxLayout();
    QLabel *radiusCheckNameLabel = new QLabel(QString("Check ID:"));
    QLabel *radiusComponentName = new QLabel();
    radiusComponentName->setObjectName("componentname");
    QLabel *radiusCheckType = new QLabel("-radius");
    radiusCheckType->setObjectName("checktype");
    QGridLayout *radiusFullNameLayout = new QGridLayout();
    radiusFullNameLayout->setHorizontalSpacing(0);
    radiusFullNameLayout->setColumnStretch(0,0);
    radiusFullNameLayout->setColumnStretch(1,5);
    radiusFullNameLayout->addWidget(radiusComponentName, 0, 0);
    radiusFullNameLayout->addWidget(radiusCheckType, 0, 1);
    QLabel *radiusComponentLabel = new QLabel(QString("Component analyzed:"));
    QComboBox *radiusComponentBox = new QComboBox();
    radiusComponentBox->setObjectName("combobox");
    setupChecksComboBox(radiusComponentBox);
    radiusComponentName->setText(radiusComponentBox->currentText());
    connect( radiusComponentBox, SIGNAL(currentIndexChanged(QString)), radiusComponentName, SLOT(setText(QString)) );
    QLabel *radiusThresholdLabel = new QLabel(QString("radius difference in decimal millimeters (10 = 1 mm):"));
    QLabel *radiusThresholdNumber = new QLabel();
    QSlider *radiusThresholdSlider = new QSlider(Qt::Horizontal);
    connect(radiusThresholdSlider, SIGNAL(valueChanged(int)), radiusThresholdNumber, SLOT(setNum(int)));
    radiusThresholdSlider->setRange(0,50);
    radiusThresholdSlider->setValue(10);
    QPushButton *radiusAdd = new QPushButton(QString("Add Check"));
    connect(radiusAdd, SIGNAL(clicked()), this, SLOT(saveCheck()));
    QPushButton *radiusAddAll = new QPushButton(QString("Add Check For Every Component"));
    connect(radiusAddAll, SIGNAL(clicked()), this, SLOT(saveCheckAll()));
    radiusTabLayout->addWidget(radiusCheckNameLabel);
    radiusTabLayout->addLayout(radiusFullNameLayout);
    radiusTabLayout->addWidget(radiusComponentLabel);
    radiusTabLayout->addWidget(radiusComponentBox);
    radiusTabLayout->addWidget(radiusThresholdLabel);
    radiusTabLayout->addWidget(radiusThresholdNumber);
    radiusTabLayout->addWidget(radiusThresholdSlider);
    radiusTabLayout->addWidget(radiusAdd);
    radiusTabLayout->addWidget(radiusAddAll);
    radiusTab->setLayout(radiusTabLayout);

    tabWidget->addTab(presenceTab, QString("Presence"));
    tabWidget->addTab(positionTab, QString("Position"));
    tabWidget->addTab(inclinationTab, QString("Inclination"));
    tabWidget->addTab(orientationTab, QString("Orientation"));
    tabWidget->addTab(colorTab, QString("Color"));
    tabWidget->addTab(heightTab, QString("Height"));
    tabWidget->addTab(radiusTab, QString("Circle Radius"));

    dialogLayout->addWidget(tabWidget);
    addCheckDialog->setLayout(dialogLayout);
    addCheckDialog->deleteLater(); // delete dialog when the control returns to the event loop from which deleteLater() was called (after exec i guess)
    dialogLayout->deleteLater(); // delete dialog layout when the control returns to the event loop from which deleteLater() was called (after exec i guess)
    addCheckDialog->resize(640, 240);
    addCheckDialog->exec();
}

void Ui::saveCheck()
{
    QTabWidget *tabWidget = addCheckDialog->findChild<QTabWidget *>("tabwidget");
    QWidget *currentWidget = tabWidget->currentWidget();
    QLabel *checkname = currentWidget->findChild<QLabel *>("componentname");
    QLabel *checkType = currentWidget->findChild<QLabel *>("checktype");
    QString fullname = checkname->text() + checkType->text();
    QComboBox *comboBox = currentWidget->findChild<QComboBox *>("combobox");
    QSlider *slider = currentWidget->findChild<QSlider *>();
    CheckType type;
    float threshold=0;
    switch (tabWidget->currentIndex())
    {
    case 0:
        threshold = slider->value()/10.0f;
        type = PRESENCE;
        break;
    case 1:
        threshold = slider->value()/10.0f;
        type = POSITION;
        break;
    case 2:
        threshold = slider->value()/10.0f;
        type = INCLINATION;
        break;
    case 3:
        threshold = slider->value()/10.0f;
        type = ORIENTATION;
        break;
    case 4:
        threshold = slider->value();
        type = COLOR;
        break;
    case 5:
        threshold = slider->value()/10.0f;
        type = HEIGHT;
        break;
    case 6:
        threshold = slider->value()/10.0f;
        type = RADIUS;
        break;
    }

    if( motor->addCheck( fullname, comboBox->currentText(), type, threshold ))
    {
        statusBar()->showMessage( QString("%1 check added to checks list.").arg(fullname) );
        checksList->addItem(fullname);
    }
    else statusBar()->showMessage( QString("Couldn't save this check: check check's name.") );
}

void Ui::saveCheckAll()
{
    QTabWidget *tabWidget = addCheckDialog->findChild<QTabWidget *>("tabwidget");
    QWidget *currentWidget = tabWidget->currentWidget();
    QComboBox *comboBox = currentWidget->findChild<QComboBox *>("combobox");
    QSlider *slider = currentWidget->findChild<QSlider *>();
    CheckType type;
    QString typeSuffix;
    float threshold=0;
    switch (tabWidget->currentIndex())
    {
    case 0:
        threshold = slider->value()/10.0f;
        type = PRESENCE;
        typeSuffix = "-presence";
        break;
    case 1:
        threshold = slider->value()/10.0f;
        type = POSITION;
        typeSuffix = "-position";
        break;
    case 2:
        threshold = slider->value()/10.0f;
        type = INCLINATION;
        typeSuffix = "-inclination";
        break;
    case 3:
        threshold = slider->value()/10.0f;
        type = ORIENTATION;
        typeSuffix = "-orientation";
        break;
    case 4:
        threshold = slider->value();
        type = COLOR;
        typeSuffix = "-color";
        break;
    case 5:
        threshold = slider->value()/10.0f;
        type = HEIGHT;
        typeSuffix = "-height";
        break;
    case 6:
        threshold = slider->value()/10.0f;
        type = RADIUS;
        typeSuffix = "-radius";
        break;
    }
    for( int i = 0; i < comboBox->count(); i++)
    {
        comboBox->setCurrentIndex(i); // set the current component index in che combo box
        QString fullname = comboBox->currentText() + typeSuffix; // compose the full name of the check with componentName + type of check suffix
        if( motor->addCheck( fullname, comboBox->currentText(), type, threshold )) // add the check to the check list of the motor
            checksList->addItem(fullname); // add check to the ui check list to be displayed
    }
}

void Ui::deleteCheck()
{
    if(checksList->selectedItems().isEmpty())
        statusBar()->showMessage("Can't delete check: no check selected.");
    else
    {
        if( motor->deleteCheck(checksList->selectedItems().first()->text()))
        {
            qDeleteAll(checksList->selectedItems()); // delete entry from components list
            statusBar()->showMessage("Check deleted.");
        }
        else statusBar()->showMessage("Can't delete check: no matching name found in checks' handler.");
    }
}

void Ui::start()
{
    time_t start,end;
    time (&start);
// INITIAL CHECKS
    if(motor->getTargetCloud()->empty())
    {
        statusBar()->showMessage(QString("Load a reference cloud before starting."));
        return;
    }
    if(motor->getSourceCloud()->empty())
    {
        statusBar()->showMessage(QString("Load a sample cloud before starting."));
        return;
    }
    if(componentsList->count() == 0)
        resultsList->append(QString("No components defined. Performing automatic difference detection."));
    else resultsList->append(QString("%1 components defined. Performing user-assisted difference detection.").arg(componentsList->count()));

// EXECUTION LOOP
    QStringListIterator sourceIterator(*filesNamesList);
    while(sourceIterator.hasNext())
    {
        resultsList->append(" ");
        resultsList->append(QString("##### Analyzing %1 cloud #####").arg( sourceIterator.peekNext() ));

    // SOURCE CLOUD LOADER
        if( motor->loadSourceCloud( pathSourceFolderField->text() + "/" + sourceIterator.peekNext() ) )
            resultsList->append( sourceIterator.peekNext() + QString(" loaded." ) );
        else resultsList->append(QString("Couldn't load the source point cloud, maybe the path or the filename are not correct anymore."));

    // REGISTRATION
        if(!motor->isRegistrationAlreadyPerformed())
        {
            motor->registration();
            resultsList->append(QString("Registration performed."));
        }

        if(componentsList->count() != 0)
        {
    // COMPONENTS MATCHING
            resultsList->append(QString("Components matching:"));
            sourceComponentsList->clear();
            motor->findSourceComponents();
            setupSourceComboBox(); // fill the source components combo box with the names of the items discovered
            resultsList->append(QString("%1 of %2 components matched.").arg(sourceComponentsList->count()).arg(componentsList->count()));

    // VERIFY SOURCE COMPONENTS PROPERTIES
            resultsList->append(QString("Components check:"));
            QMap<QString, bool> results = motor->performChecks();
            QMapIterator<QString, bool> resultsIterator(results);
            if( results.keys(false).count() == 0 )
                resultsList->append( QString("0 errors."));
            while (resultsIterator.hasNext())
            {
                if(resultsIterator.next().value() == false)
                    resultsList->append( QString("%1 : ERROR").arg(resultsIterator.key()));
            }
        }
        else
        {
            int numberOfErrors =motor->segmentDifferences();
            resultsList->append( QString("Number of wrong components: %1").arg(numberOfErrors) );
        }

        resultsList->append(QString("##### Cloud %1 analyzed #####").arg(sourceIterator.peekNext()));
        sourceIterator.next(); // advance the iterator
    }
    time (&end);
    double dif = difftime (end,start);
    cout << "------------------------------------->  Finished in " << dif << " seconds"<< endl;
}

void Ui::showTarget()
{
    if(!viewer->removePointCloud("target"))
    {
        pcl::PointCloud<pcl::PointXYZRGB>::Ptr targetWithComponents(new pcl::PointCloud<pcl::PointXYZRGB>); // DEBUG, DEVE MOSTRARE LA CLOUD "PURA" E POI PERMETTERE DI EVIDENIZIARLI
        pcl::copyPointCloud( *(motor-> getTargetCloud()),*targetWithComponents); // DEBUG
        motor->colorComponents(targetWithComponents, motor->getTargetComponentsList()); // DEBUG
        pcl::visualization::PointCloudColorHandlerRGBField<pcl::PointXYZRGB> rgb(targetWithComponents);
        viewer->addPointCloud<pcl::PointXYZRGB>(targetWithComponents, rgb, "target");
        if(!isCameraCentered)
        {
            viewer->resetCamera();
            isCameraCentered = true;
        }
        statusBar()->showMessage(QString("Target point cloud added to the visualizer."));
    }
    else statusBar()->showMessage(QString("Target point cloud removed from the visualizer."));
    qvtkVisualizer->update();
}

void Ui::showSource()
{
    if(!viewer->removePointCloud("source"))
    {
        pcl::visualization::PointCloudColorHandlerRGBField<pcl::PointXYZRGB> rgb(motor->getSourceCloud());
        viewer->addPointCloud<pcl::PointXYZRGB>(motor->getSourceCloud(), rgb, "source");
        if(!isCameraCentered)
        {
            viewer->resetCamera();
            isCameraCentered = true;
        }
        statusBar()->showMessage(QString("Source point cloud added to the visualizer."));
    }
    else statusBar()->showMessage(QString("Source point cloud removed from the visualizer."));
    qvtkVisualizer->update();
}

void Ui::showRegistered()
{
    if(!viewer->removePointCloud("registered"))
    {
        pcl::PointCloud<pcl::PointXYZRGB>::Ptr registeredWithComponents(new pcl::PointCloud<pcl::PointXYZRGB>); // DEBUG, DEVE MOSTRARE LA CLOUD "PURA" E POI PERMETTERE DI EVIDENIZIARLI
        pcl::copyPointCloud( *(motor->getRegisteredCloud()),*registeredWithComponents); // DEBUG
        motor->colorComponents(registeredWithComponents, motor->getSourceComponentsList()); // color the components with random colours
        pcl::visualization::PointCloudColorHandlerRGBField<pcl::PointXYZRGB> rgb(registeredWithComponents);
        viewer->addPointCloud<pcl::PointXYZRGB>(registeredWithComponents, rgb, "registered");
        if(!isCameraCentered)
        {
            viewer->resetCamera();
            isCameraCentered = true;
        }
        statusBar()->showMessage(QString("Registered point cloud added to the visualizer."));
    }
    else statusBar()->showMessage(QString("Registered point cloud removed from the visualizer."));
    qvtkVisualizer->update();
}


void Ui::showDifference()
{
    if(!viewer->removePointCloud("difference"))
    {
        pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZRGB> rgb(motor->getDifferenceCloud(), 255, 0, 0); // color the difference cloud in red
        viewer->addPointCloud<pcl::PointXYZRGB>(motor->getDifferenceCloud(), rgb, "difference");
        if(!isCameraCentered)
        {
            viewer->resetCamera();
            isCameraCentered = true;
        }
        statusBar()->showMessage(QString("Difference point cloud added to the visualizer."));
    }
    else statusBar()->showMessage(QString("Difference point cloud removed from the visualizer."));
    qvtkVisualizer->update();
}

void Ui::showTargetComponent(QListWidgetItem* item)
{
    if(item->text() == "")
        return;
    if(  !viewer->removePointCloud( item->text().toStdString()+"trg" )  )
    {
        pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZRGB> rgb( motor->getTargetComponentCloud(item->text()), 0, 255, 0);
        viewer->addPointCloud<pcl::PointXYZRGB>( motor->getTargetComponentCloud(item->text()), rgb, item->text().toStdString()+"trg" );
        viewer->resetCamera();
        statusBar()->showMessage(QString("%1 point cloud removed from the visualizer.").arg(item->text()));
    }
    else statusBar()->showMessage(QString("%1 point cloud added to the visualizer.").arg(item->text()));
    qvtkVisualizer->update();
}

void Ui::showSourceComponent()
{
    if(sourceComponentsList->currentText() == "")
        return;
    if( !viewer->removePointCloud( sourceComponentsList->currentText().toStdString()+"src" ) )
    {
        pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZRGB> rgb( motor->getSourceComponentCloud(sourceComponentsList->currentText()), 255, 0, 0);
        viewer->addPointCloud<pcl::PointXYZRGB>( motor->getSourceComponentCloud(sourceComponentsList->currentText()), rgb, sourceComponentsList->currentText().toStdString()+"src" );
        viewer->resetCamera();
        statusBar()->showMessage(QString("%1 point cloud removed from the visualizer.").arg(sourceComponentsList->currentText()));
    }
    else statusBar()->showMessage(QString("%1 point cloud added to the visualizer.").arg(sourceComponentsList->currentText()));
    qvtkVisualizer->update();
}

// UI FUNCTIONS

void Ui::setupMenuBar()
{
    QAction* quitAct = new QAction(tr("&Quit"), this);
    quitAct->setShortcuts(QKeySequence::Quit);
    quitAct->setStatusTip(tr("Quit the application"));
    connect(quitAct, SIGNAL(triggered()), this, SLOT(close()));
    QAction* aboutAct = new QAction(tr("&About"), this);
    aboutAct->setStatusTip(tr("Show the application's About box"));
    connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));
    QAction* aboutQtAct = new QAction(tr("About &Qt"), this);
    aboutQtAct->setStatusTip(tr("Show the Qt library's About box"));
    connect(aboutQtAct, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
    QAction* aboutPCLAct = new QAction(tr("About &PCL"), this);
    aboutPCLAct->setStatusTip(tr("Show the PCL library's About box"));
    connect(aboutPCLAct, SIGNAL(triggered()), this, SLOT(aboutPCL()));
    QMenu* fileMenu = menuBar()->addMenu(tr("&File"));
    fileMenu->addAction(quitAct);
    QMenu* helpMenu = menuBar()->addMenu(tr("&Help"));
    helpMenu->addAction(aboutAct);
    helpMenu->addAction(aboutQtAct);
    helpMenu->addAction(aboutPCLAct);
}

void Ui::setupStatusBar()
{
    statusBar()->showMessage(tr("Ready"));
}

void Ui::setupLoadTBox()
{
    loadTBox = new QGroupBox(QString("Load Reference Cloud"));
    QPushButton* browseTButton = new QPushButton(QString("Browse..."));
    connect(browseTButton, SIGNAL(clicked()), this, SLOT(browseLoadTarget()));
    pathTField = new QLineEdit();
    QHBoxLayout* loadTargetLayout = new QHBoxLayout;
    loadTargetLayout->addWidget(browseTButton);
    loadTargetLayout->addWidget(pathTField);
    loadTBox->setLayout(loadTargetLayout);
}

void Ui::setupComponentsBox()
{
    componentsBox = new QGroupBox(QString("Components Definition"));
    QHBoxLayout* componentButtonsLayout = new QHBoxLayout;
    QPushButton* addComponentButton = new QPushButton(QString("Add..."));
    connect(addComponentButton, SIGNAL(clicked()), this, SLOT(openComponentDialog()));
    QPushButton* delComponentButton = new QPushButton(QString("Delete"));
    connect(delComponentButton, SIGNAL(clicked()), this, SLOT(deleteComponent()));
    componentButtonsLayout->addWidget(addComponentButton);
    componentButtonsLayout->addWidget(delComponentButton);
    QVBoxLayout* componentsLayout = new QVBoxLayout;
    componentsList = new QListWidget;
    componentsList->setSelectionMode(QAbstractItemView::SingleSelection);
    connect(componentsList, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(showTargetComponent(QListWidgetItem*)));
    QPushButton* autoComponentDetectionButton = new QPushButton(QString("Automatic Component Detection"));
    connect(autoComponentDetectionButton, SIGNAL(clicked()), this, SLOT(autoComponentDetection()));
    componentsLayout->addLayout(componentButtonsLayout);
    componentsLayout->addWidget(componentsList);
    componentsLayout->addWidget(autoComponentDetectionButton);
    componentsBox->setLayout(componentsLayout);
}

void Ui::setupChecksBox()
{
    checksBox = new QGroupBox(QString("Checks Definition"));
    QHBoxLayout* checkButtonsLayout = new QHBoxLayout;
    QPushButton* addCheckButton = new QPushButton(QString("Add..."));
    connect(addCheckButton, SIGNAL(clicked()), this, SLOT(openCheckDialog()));
    QPushButton* delCheckButton = new QPushButton(QString("Delete"));
    connect(delCheckButton, SIGNAL(clicked()), this, SLOT(deleteCheck()));
    checkButtonsLayout->addWidget(addCheckButton);
    checkButtonsLayout->addWidget(delCheckButton);
    QVBoxLayout* checksLayout = new QVBoxLayout;
    checksList = new QListWidget;
    checksLayout->addLayout(checkButtonsLayout);
    checksLayout->addWidget(checksList);
    checksBox->setLayout(checksLayout);
}

void Ui::setupLoadSBox()
{
    QPushButton* browseSourceFolderButton = new QPushButton(QString("Folder..."));
    connect(browseSourceFolderButton, SIGNAL(clicked()), this, SLOT(browseSourceFolder()));
    pathSourceFolderField = new QLineEdit;
    QHBoxLayout* loadMultiSourceLayout = new QHBoxLayout;
    loadMultiSourceLayout->addWidget(browseSourceFolderButton);
    loadMultiSourceLayout->addWidget(pathSourceFolderField);
    sourceCloudsComboBox = new QComboBox;
    connect(sourceCloudsComboBox, SIGNAL(activated(QString)), this, SLOT(loadSourceCloud(QString)));

    QVBoxLayout* loadSourceLayout = new QVBoxLayout;
    loadSourceLayout->addLayout(loadMultiSourceLayout);
    loadSourceLayout->addWidget(sourceCloudsComboBox);
    loadSBox = new QGroupBox(QString("Load Sample Cloud"));
    loadSBox->setLayout(loadSourceLayout);
}

void Ui::setupVisualizer()
{
    qvtkVisualizer = new QVTKWidget();// create qvtk widget
    viewer = new pcl::visualization::PCLVisualizer("3DViewer", false);// don't display in the vtk visualizer, render it on a qt window
    qvtkVisualizer->SetRenderWindow(viewer->getRenderWindow());// set as render window the render window of the pcl visualizer
    viewer->setupInteractor(qvtkVisualizer->GetInteractor(), qvtkVisualizer->GetRenderWindow());// tells the visualizer what interactor is using now and for what window
    viewer->getInteractorStyle()->setKeyboardModifier(pcl::visualization::INTERACTOR_KB_MOD_SHIFT);// ripristina input system of original visualizer (shift+click for points)
    viewer->setBackgroundColor(0.5, 0.5, 0.5);
    viewer->initCameraParameters();
    viewer->registerPointPickingCallback(&pointPickCallback, this); // callback function for interaction with the mouse on the visualizer
}

void Ui::setupResultsBox()
{
    resultsBox = new QGroupBox(QString("Analysis Results"));
    resultsBox->setMaximumHeight(200);
    QPushButton* startButton = new QPushButton(QString("START!"));
    QSlider* scoreDistanceThresholdSetter = new QSlider();
    scoreDistanceThresholdSetter->setRange(0,100);
    scoreDistanceThresholdSetter->setValue(20);
    scoreDistanceThresholdSetter->setObjectName("scoreDistanceSlider");
    connect(scoreDistanceThresholdSetter,SIGNAL(sliderReleased()),this, SLOT(setScoreDistanceThreshold()));
    connect(startButton, SIGNAL(clicked()), this, SLOT(start()));
    resultsList = new QTextEdit;
    resultsList->setReadOnly(true);
    QHBoxLayout* resultsLayout = new QHBoxLayout;
    resultsLayout->addWidget(startButton);
    resultsLayout->addWidget(scoreDistanceThresholdSetter);
    resultsLayout->addWidget(resultsList);
    resultsBox->setLayout(resultsLayout);
}

void Ui::setupVisualizerCommandsBox()
{
    visualizerCommandsBox = new QGroupBox("Visualizer Commands");
    QVBoxLayout* visualizerCommandsLayout = new QVBoxLayout;
    QPushButton* showTButton = new QPushButton(QString("Show/Hide Target Cloud"));
    connect(showTButton, SIGNAL(clicked()), this, SLOT(showTarget()));
    QPushButton* showSButton = new QPushButton(QString("Show/Hide Source Cloud"));
    connect(showSButton, SIGNAL(clicked()), this, SLOT(showSource()));
    QPushButton* showRButton = new QPushButton(QString("Show/Hide Registered Cloud"));
    connect(showRButton, SIGNAL(clicked()), this, SLOT(showRegistered()));
    QPushButton* showDButton = new QPushButton(QString("Show/Hide Difference Cloud"));
    connect(showDButton, SIGNAL(clicked()), this, SLOT(showDifference()));
    QPushButton* clearAllButton = new QPushButton(QString("Clear All Clouds"));
    connect(clearAllButton, SIGNAL(clicked()), this, SLOT(clearAll()));
    QPushButton* showSComponentButton = new QPushButton(QString("Show/Hide Source Component"));
    connect(showSComponentButton, SIGNAL(clicked()), this, SLOT(showSourceComponent()));
    sourceComponentsList = new QComboBox;
    QHBoxLayout* showSourceComponentLayout = new QHBoxLayout;
    showSourceComponentLayout->addWidget(showSComponentButton);
    showSourceComponentLayout->addWidget(sourceComponentsList);

    visualizerCommandsLayout->addWidget(showTButton);
    visualizerCommandsLayout->addWidget(showSButton);
    visualizerCommandsLayout->addWidget(showRButton);
    visualizerCommandsLayout->addWidget(showDButton);
    visualizerCommandsLayout->addLayout(showSourceComponentLayout);
    visualizerCommandsLayout->addWidget(clearAllButton);

    visualizerCommandsBox->setLayout(visualizerCommandsLayout);
}

void Ui::setupMainLayout()
{
    QWidget* mainWidget = new QWidget;
    QHBoxLayout* mainLayout = new QHBoxLayout;
    QVBoxLayout* viewerLayout = new QVBoxLayout;
    QVBoxLayout* commandsLayout = new QVBoxLayout;

    setupLoadTBox();
    setupComponentsBox();
    setupChecksBox();
    setupLoadSBox();
    setupVisualizer();
    setupResultsBox();
    setupVisualizerCommandsBox();

    loadTBox->setMaximumWidth(400);
    componentsBox->setMaximumWidth(400);
    checksBox->setMaximumWidth(400);
    loadSBox->setMaximumWidth(400);
    commandsLayout->addWidget(loadTBox);
    commandsLayout->addWidget(componentsBox);
    commandsLayout->addWidget(checksBox);
    commandsLayout->addWidget(loadSBox);

    viewerLayout->addWidget(qvtkVisualizer);
    viewerLayout->addWidget(resultsBox);
    viewerLayout->addWidget(visualizerCommandsBox);

    mainLayout->addLayout(commandsLayout);
    mainLayout->addLayout(viewerLayout);

    mainWidget->setLayout(mainLayout);
    setCentralWidget(mainWidget);
}

void Ui::pointPickCallback(const pcl::visualization::PointPickingEvent& event, void* cookie)
{
    Ui *ui = (Ui*)cookie;
    float x,y,z;
    if (event.getPointIndex() == -1)
        ui->statusBar()->showMessage(tr("No point was clicked"));
    else
    {
        event.getPoint(x,y,z);
        ui->statusBar()->showMessage(QString("Point Clicked index: %1 x: %2 y: %3 z: %4")
                                     .arg(event.getPointIndex())
                                     .arg(x)
                                     .arg(y)
                                     .arg(z)
                                     );
    }
}

void Ui::pointPickCallbackSelectComponent(const pcl::visualization::PointPickingEvent& event, void* cookie)
{
    Ui *ui = (Ui*)cookie;
    float x,y,z;
    if (event.getPointIndex() == -1)
        ui->statusBar()->showMessage(tr("No point was clicked"));
    else
    {
        event.getPoint(x,y,z);
        ui->statusBar()->showMessage(QString("Point Clicked index: %1 x: %2 y: %3 z: %4")
                                     .arg(event.getPointIndex())
                                     .arg(x)
                                     .arg(y)
                                     .arg(z)
                                     );
        QPushButton *colorbox = ui->getComponentDialog()->findChild<QPushButton *>("colorbox");
        colorbox->setStyleSheet(colorToStyleSheet(ui->getMotor()->getPointColor(event.getPointIndex())));
        ui->getMotor()->componentSelection(event.getPointIndex());
        ui->getDialogViewer()->updatePointCloud(ui->getMotor()->getNewComponentCloud(),"cloud");
    }
}

QString Ui::colorToStyleSheet(QColor *color)
{
    QString styleSheet = QString("* { background-color: rgb(%1,%2,%3) }")
            .arg(color->red())
            .arg(color->green())
            .arg(color->blue());
    return styleSheet;
}

void Ui::setupSourceComboBox()
{
    QMap<QString, Component> *list = motor->getSourceComponentsList();
    QMapIterator<QString, Component> iter(*list);
    while (iter.hasNext())
    {
        iter.next(); // step to the next item
        sourceComponentsList->addItem(iter.key()); //get the key of the item, i.e. the name of the component
    }
}

void Ui::setupChecksComboBox(QComboBox *cb)
{
    QMap<QString, Component> *list = motor->getTargetComponentsList();
    QMapIterator<QString, Component> iter(*list);
    while (iter.hasNext())
    {
        iter.next(); // step to the next item
        cb->addItem(iter.key()); //get the key of the item, i.e. the name of the component
    }
}
